#include <stdlib.h>
#include <stdio.h>
#include "slave.h"
#include "task.h"
#include "ldm_malloc.h"
#include "sparselu_acemesh.h"

extern int bots_arg_size_1;
__thread_local_fix int local_bots_arg_size_1;

#ifdef USE_LDM
__thread_local float arr_a[BOTS_APP_DEF_ARG_SIZE_1 * BOTS_APP_DEF_ARG_SIZE_1];
__thread_local float arr_b[BOTS_APP_DEF_ARG_SIZE_1 * BOTS_APP_DEF_ARG_SIZE_1];
__thread_local float arr_c[BOTS_APP_DEF_ARG_SIZE_1 * BOTS_APP_DEF_ARG_SIZE_1];
#endif

/***********************************************************************
 * lu0: 
 **********************************************************************/
void slave_lu0(float *diag)
{
   int i, j, k;
   local_bots_arg_size_1=bots_arg_size_1;
#ifdef USE_LDM
   volatile int get_reply = 0;
   int tsize = 0;
#ifdef TASK_FLOW
/*
   int flow = 0;
   int limit = 0;
   for (flow = 0; flow < local_bots_arg_size_1; flow += 64) {
      if (local_bots_arg_size_1 - flow > 64) {
         tsize = 64 * 64 * sizeof(float);
         athread_get(PE_MODE, diag + flow, arr_a,
                  tsize, (void *)&get_reply, 0, 0, 0);
         while (get_reply != 1)
            ;

         for (k=0; k<64; k++)
         for (i=k+1; i<64; i++)
         {
            arr_a[i*64+k] = arr_a[i*64+k] / arr_a[k*64+k];
            for (j=k+1; j<64; j++)
               arr_a[i*64+j] = arr_a[i*64+j] - arr_a[i*64+k] * arr_a[k*64+j];
         }
      }
      else {
         tsize = (local_bots_arg_size_1 - flow) * (local_bots_arg_size_1 - flow) * sizeof(float);
         athread_get(PE_MODE, diag + flow, arr_a,
                  tsize, (void *)&get_reply, 0, 0, 0);
         while (get_reply != 1)
            ;

         limit = local_bots_arg_size_1 - flow;
         for (k=0; k<limit; k++)
         for (i=k+1; i<limit; i++)
         {
            arr_a[i*limit+k] = arr_a[i*limit+k] / arr_a[k*limit+k];
            for (j=k+1; j<limit; j++)
               arr_a[i*limit+j] = arr_a[i*limit+j] - arr_a[i*limit+k] * arr_a[k*limit+j];
         }
      }

      get_reply = 0;
      athread_put(PE_MODE, arr_a, diag + flow,
                  tsize, (void *)&get_reply, 0, 0, 0);
      while (get_reply != 1)
         ;
      get_reply = 0;
   }


   difficult to write blocks code...


*/
#else
   tsize = BOTS_APP_DEF_ARG_SIZE_1 * BOTS_APP_DEF_ARG_SIZE_1 * sizeof(float);
   athread_get(PE_MODE, diag, arr_a,
               tsize, (void *)&get_reply, 0, 0, 0);
   while (get_reply != 1)
      ;

   for (k=0; k<local_bots_arg_size_1; k++)
      for (i=k+1; i<local_bots_arg_size_1; i++)
      {
         arr_a[i*local_bots_arg_size_1+k] = arr_a[i*local_bots_arg_size_1+k] / arr_a[k*local_bots_arg_size_1+k];
         for (j=k+1; j<local_bots_arg_size_1; j++)
            arr_a[i*local_bots_arg_size_1+j] = arr_a[i*local_bots_arg_size_1+j] - arr_a[i*local_bots_arg_size_1+k] * arr_a[k*local_bots_arg_size_1+j];
      }

   get_reply = 0;
   athread_put(PE_MODE, arr_a, diag,
               tsize, (void *)&get_reply, 0, 0);
   while (get_reply != 1)
      ;
#endif

#else

   for (k=0; k<local_bots_arg_size_1; k++)
      for (i=k+1; i<local_bots_arg_size_1; i++)
      {
         diag[i*local_bots_arg_size_1+k] = diag[i*local_bots_arg_size_1+k] / diag[k*local_bots_arg_size_1+k];
         for (j=k+1; j<local_bots_arg_size_1; j++)
            diag[i*local_bots_arg_size_1+j] = diag[i*local_bots_arg_size_1+j] - diag[i*local_bots_arg_size_1+k] * diag[k*local_bots_arg_size_1+j];
      }
#endif
}

/***********************************************************************
 * bdiv: 
 **********************************************************************/
void slave_bdiv(float *diag, float *row)
{
   int i, j, k;
   local_bots_arg_size_1=bots_arg_size_1;
#ifdef USE_LDM
   volatile int get_reply = 0;
   int tsize = 0;
   tsize = BOTS_APP_DEF_ARG_SIZE_1 * BOTS_APP_DEF_ARG_SIZE_1 * sizeof(float);
   athread_get(PE_MODE, diag, arr_a,
               tsize, (void *)&get_reply, 0, 0, 0);
   athread_get(PE_MODE, row, arr_b,
               tsize, (void *)&get_reply, 0, 0, 0);
   while (get_reply != 2)
      ;

   for (i=0; i<local_bots_arg_size_1; i++)
      for (k=0; k<local_bots_arg_size_1; k++)
      {
         arr_b[i*local_bots_arg_size_1+k] = arr_b[i*local_bots_arg_size_1+k] / arr_a[k*local_bots_arg_size_1+k];
         for (j=k+1; j<local_bots_arg_size_1; j++)
            arr_b[i*local_bots_arg_size_1+j] = arr_b[i*local_bots_arg_size_1+j] - arr_b[i*local_bots_arg_size_1+k]*arr_a[k*local_bots_arg_size_1+j];
      }

   get_reply = 0;
   athread_put(PE_MODE, arr_a, diag,
               tsize, (void *)&get_reply, 0, 0);
   athread_put(PE_MODE, arr_b, row,
               tsize, (void *)&get_reply, 0, 0);
   while (get_reply != 2)
      ;
#else
   for (i=0; i<local_bots_arg_size_1; i++)
      for (k=0; k<local_bots_arg_size_1; k++)
      {
         row[i*local_bots_arg_size_1+k] = row[i*local_bots_arg_size_1+k] / diag[k*local_bots_arg_size_1+k];
         for (j=k+1; j<local_bots_arg_size_1; j++)
            row[i*local_bots_arg_size_1+j] = row[i*local_bots_arg_size_1+j] - row[i*local_bots_arg_size_1+k]*diag[k*local_bots_arg_size_1+j];
      }
#endif
}
/***********************************************************************
 * bmod: 
 **********************************************************************/
void slave_bmod(float *row, float *col, float *inner)
{
   int i, j, k;
   local_bots_arg_size_1=bots_arg_size_1;
#ifdef USE_LDM
   volatile int get_reply = 0;
   int tsize = 0;
   tsize = BOTS_APP_DEF_ARG_SIZE_1 * BOTS_APP_DEF_ARG_SIZE_1 * sizeof(float);
   athread_get(PE_MODE, row, arr_a,
               tsize, (void *)&get_reply, 0, 0, 0);
   athread_get(PE_MODE, col, arr_b,
               tsize, (void *)&get_reply, 0, 0, 0);
   athread_get(PE_MODE, inner, arr_c,
               tsize, (void *)&get_reply, 0, 0, 0);
   while (get_reply != 3)
      ;

   for (i=0; i<local_bots_arg_size_1; i++)
      for (j=0; j<local_bots_arg_size_1; j++)
         for (k=0; k<local_bots_arg_size_1; k++)
            arr_c[i*local_bots_arg_size_1+j] = arr_c[i*local_bots_arg_size_1+j] - arr_a[i*local_bots_arg_size_1+k]*arr_b[k*local_bots_arg_size_1+j];

   get_reply = 0;
   athread_put(PE_MODE, arr_a, row,
               tsize, (void *)&get_reply, 0, 0);
   athread_put(PE_MODE, arr_b, col,
               tsize, (void *)&get_reply, 0, 0);
   athread_put(PE_MODE, arr_c, inner,
               tsize, (void *)&get_reply, 0, 0);
   while (get_reply != 3)
      ;
#else
   for (i=0; i<local_bots_arg_size_1; i++)
      for (j=0; j<local_bots_arg_size_1; j++)
         for (k=0; k<local_bots_arg_size_1; k++)
            inner[i*local_bots_arg_size_1+j] = inner[i*local_bots_arg_size_1+j] - row[i*local_bots_arg_size_1+k]*col[k*local_bots_arg_size_1+j];
#endif
}
/***********************************************************************
 * fwd: 
 **********************************************************************/
void slave_fwd(float *diag, float *col)
{
   int i, j, k;
   local_bots_arg_size_1=bots_arg_size_1;
#ifdef USE_LDM
   volatile int get_reply = 0;
   int tsize = 0;
   tsize = BOTS_APP_DEF_ARG_SIZE_1 * BOTS_APP_DEF_ARG_SIZE_1 * sizeof(float);
   athread_get(PE_MODE, diag, arr_a,
               tsize, (void *)&get_reply, 0, 0, 0);
   athread_get(PE_MODE, col, arr_b,
               tsize, (void *)&get_reply, 0, 0, 0);
   while (get_reply != 2)
      ;

   for (j=0; j<local_bots_arg_size_1; j++)
      for (k=0; k<local_bots_arg_size_1; k++) 
         for (i=k+1; i<local_bots_arg_size_1; i++)
            arr_b[i*local_bots_arg_size_1+j] = arr_b[i*local_bots_arg_size_1+j] - arr_a[i*local_bots_arg_size_1+k]*arr_b[k*local_bots_arg_size_1+j];

   get_reply = 0;
   athread_put(PE_MODE, arr_a, diag,
               tsize, (void *)&get_reply, 0, 0);
   athread_put(PE_MODE, arr_b, col,
               tsize, (void *)&get_reply, 0, 0);
   while (get_reply != 2)
      ;
#else
   for (j=0; j<local_bots_arg_size_1; j++)
      for (k=0; k<local_bots_arg_size_1; k++) 
         for (i=k+1; i<local_bots_arg_size_1; i++)
            col[i*local_bots_arg_size_1+j] = col[i*local_bots_arg_size_1+j] - diag[i*local_bots_arg_size_1+k]*col[k*local_bots_arg_size_1+j];
#endif
}


void __slave_lu0(LU0ARG * arg)
{
   slave_lu0(arg->diag);
}

void __slave_fwd(FWDARG * arg)
{
   slave_fwd(arg->diag, arg->col);
}

void __slave_bdiv(BDIVARG * arg)
{
   slave_bdiv(arg->diag, arg->row);
}

void __slave_bmod(BMODARG * arg)
{
   slave_bmod(arg->row, arg->col, arg->inner);
}
